跳到主要内容

如何区分渲染进程卡死和主进程阻塞?

考察点​

  • 多进程里“界面卡住”有两种根
  • 用窗口数量和 CPU 归属把它们分开

参考答案​

1. 现象不同​

渲染进程卡死主进程阻塞
范围通常一个窗口无响应,别的窗口还能点所有窗口一起拖不动,托盘菜单也迟缓
事件这个窗口触发 unresponsive往往没有单个窗口的 unresponsive,或全部一起触发
CPU那个渲染进程 CPU 高,或内存涨到被杀主进程 CPU 高,渲染进程在等 IPC
常见原因死循环、超大 JSON、同步布局同步读大文件、同步数据库扫全表、sendSync 堆积

主进程是所有窗口的 IPC 枢纽。它一忙,每个 invoke 都在等,看起来像“每个页面都卡了”。

2. 怎么确认​

const metrics = app.getAppMetrics();
// 看 type 为 Browser(主进程)还是 Tab(渲染进程),以及 cpu.percent

同时看是不是只有一个 webContents 进入了 unresponsive。

开发时主进程加 --inspect=9229,卡死时录 CPU profile。渲染进程用窗口里的 Performance 面板。profile 里如果主进程栈停在 fs.readFileSync 或 better-sqlite3,就不要去优化 React。

3. 处理方式也不同​

渲染进程无响应:提示等待或 reload 这个窗口,草稿靠页面自己的本地暂存恢复。

主进程阻塞:reload 窗口没有用,因为新的 invoke 还是进同一个卡住的主进程。要把同步重活移走,并避免在 IPC handler 里做全表扫描。已经卡死的主进程只能等它回到事件循环,或者靠外部守护把整个应用重启。

4. 一条判断题​

问自己:托盘右键菜单能不能马上弹出来?菜单在主进程。菜单都弹不出,就是主进程;菜单正常、只有页面不转,就是那个渲染进程。

面试话术​

一个窗口无响应、别的窗口和托盘还正常,是渲染进程,看 unresponsive,必要时重载这一窗。所有窗口和托盘一起卡,是主进程堵住了事件循环,重载页面没用,要查同步 IO 和同步数据库,把重活放到 utilityProcess。用 getAppMetrics 看 CPU 在 Browser 还是 Tab 上。

常见追问​

  • GPU 进程卡死像哪一种? 画面花或停,但 JS 定时器可能还在。render-process-gone 的 reason 和 GPU 崩溃日志能分开。可以准备关闭硬件加速的启动参数做对照。
  • invoke 一直不返回怎么查? 先看主进程 handler 有没有执行完。没执行到就是队列堵了;执行完没回到页面,再查渲染进程是不是已经重载、把这次 Promise 丢了。